package com.fanxuankai.boot.canal.client.autoconfigure;

import com.fanxuankai.boot.canal.client.EntryWrapper;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;

/**
 * canal参数配置
 *
 * @author fanxuankai
 */
@ConfigurationProperties(prefix = CanalClientProperties.PREFIX)
public class CanalClientProperties {
    public static final String PREFIX = "fxk.canal.client";
    public static final String ENABLED = PREFIX + ".enabled";
    /**
     * 是否开启 canal client
     */
    private boolean enabled = true;
    /**
     * 应用 id, 用于 canal client 抢占式运行、binlog offset 防重, 默认取 instance
     */
    private String id;

    /**
     * zk 集群
     */
    private String nodes;

    /**
     * 单节点配置
     */
    @NestedConfigurationProperty
    private SingleNode singleNode = new SingleNode();

    /**
     * 实例
     */
    private String instance = "example";

    /**
     * 过滤
     */
    private String filter = ".*\\..*";

    /**
     * 账号
     */
    private String username = "canal";

    /**
     * 密码
     */
    private String password = "canal";

    /**
     * 拉取数据的间隔 ms
     */
    private long intervalMillis = 1_000;

    /**
     * 客户端重连的间隔 ms
     */
    private long reconnectMillis = 5_000;

    /**
     * 拉取数据的数量
     */
    private int batchSize = 100;

    /**
     * 打印事件日志
     */
    private boolean showEventLog = true;

    /**
     * 打印 Entry 日志
     */
    private boolean showEntryLog = true;

    /**
     * 打印数据明细日志
     */
    private boolean showRowChange;

    /**
     * 格式化数据明细日志
     */
    private boolean formatRowChangeLog;

    /**
     * 批次达到一定数量进行并行处理, 且确保顺序消费
     */
    private int performanceThreshold = 10_000;

    /**
     * 跳过处理
     */
    private boolean skip;

    /**
     * 全局逻辑删除字段
     */
    private String logicDeleteField = "deleted";

    /**
     * 开启逻辑删除
     */
    private boolean enableLogicDelete;

    /**
     * 抢占式运行参数
     */
    private Preemptive preemptive = new Preemptive();

    /**
     * 相同 schema、table、eventType, 合并为一个 Entry
     */
    @NestedConfigurationProperty
    private MergeEntry mergeEntry = new MergeEntry();

    /**
     * 钉钉推送参数
     */
    @NestedConfigurationProperty
    private DingTalk dingTalk = new DingTalk();

    /**
     * 检查 canal 服务端
     */
    @NestedConfigurationProperty
    private CheckServer checkServer = new CheckServer();

    /**
     * 处理配置
     */
    private Handle handle = new Handle();

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getId() {
        return StringUtils.hasText(id) ? id : instance;
    }

    public void setId(String id) {
        this.id = id;
    }

    public SingleNode getSingleNode() {
        return singleNode;
    }

    public void setSingleNode(SingleNode singleNode) {
        this.singleNode = singleNode;
    }

    public String getNodes() {
        return nodes;
    }

    public void setNodes(String nodes) {
        this.nodes = nodes;
    }

    public String getInstance() {
        return instance;
    }

    public void setInstance(String instance) {
        this.instance = instance;
    }

    public String getFilter() {
        return filter;
    }

    public void setFilter(String filter) {
        this.filter = filter;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public long getIntervalMillis() {
        return intervalMillis;
    }

    public void setIntervalMillis(long intervalMillis) {
        this.intervalMillis = intervalMillis;
    }

    public long getReconnectMillis() {
        return reconnectMillis;
    }

    public void setReconnectMillis(long reconnectMillis) {
        this.reconnectMillis = reconnectMillis;
    }

    public int getBatchSize() {
        return batchSize;
    }

    public void setBatchSize(int batchSize) {
        this.batchSize = batchSize;
    }

    public boolean isShowEventLog() {
        return showEventLog;
    }

    public void setShowEventLog(boolean showEventLog) {
        this.showEventLog = showEventLog;
    }

    public boolean isShowEntryLog() {
        return showEntryLog;
    }

    public void setShowEntryLog(boolean showEntryLog) {
        this.showEntryLog = showEntryLog;
    }

    public boolean isShowRowChange() {
        return showRowChange;
    }

    public void setShowRowChange(boolean showRowChange) {
        this.showRowChange = showRowChange;
    }

    public boolean isFormatRowChangeLog() {
        return formatRowChangeLog;
    }

    public void setFormatRowChangeLog(boolean formatRowChangeLog) {
        this.formatRowChangeLog = formatRowChangeLog;
    }

    public int getPerformanceThreshold() {
        return performanceThreshold;
    }

    public void setPerformanceThreshold(int performanceThreshold) {
        this.performanceThreshold = performanceThreshold;
    }

    public boolean isSkip() {
        return skip;
    }

    public void setSkip(boolean skip) {
        this.skip = skip;
    }

    public String getLogicDeleteField() {
        return logicDeleteField;
    }

    public void setLogicDeleteField(String logicDeleteField) {
        this.logicDeleteField = logicDeleteField;
    }

    public boolean isEnableLogicDelete() {
        return enableLogicDelete;
    }

    public void setEnableLogicDelete(boolean enableLogicDelete) {
        this.enableLogicDelete = enableLogicDelete;
    }

    public Preemptive getPreemptive() {
        return preemptive;
    }

    public void setPreemptive(Preemptive preemptive) {
        this.preemptive = preemptive;
    }

    public MergeEntry getMergeEntry() {
        return mergeEntry;
    }

    public void setMergeEntry(MergeEntry mergeEntry) {
        this.mergeEntry = mergeEntry;
    }

    public DingTalk getDingTalk() {
        return dingTalk;
    }

    public void setDingTalk(DingTalk dingTalk) {
        this.dingTalk = dingTalk;
    }

    public CheckServer getCheckServer() {
        return checkServer;
    }

    public void setCheckServer(CheckServer checkServer) {
        this.checkServer = checkServer;
    }

    private Map<String, Map<String, ConsumerConfig>> consumerConfigMap = Collections.emptyMap();

    public Map<String, Map<String, ConsumerConfig>> getConsumerConfigMap() {
        return consumerConfigMap;
    }

    public void setConsumerConfigMap(Map<String, Map<String, ConsumerConfig>> consumerConfigMap) {
        this.consumerConfigMap = consumerConfigMap;
    }

    public String getTopic(EntryWrapper entryWrapper) {
        return getConsumerConfig(entryWrapper).map(ConsumerConfig::getTopic).orElse(null);
    }

    public Optional<ConsumerConfig> getConsumerConfig(EntryWrapper entryWrapper) {
        return Optional.ofNullable(consumerConfigMap)
                .map(map -> map.get(entryWrapper.getSchemaName()))
                .map(map -> map.get(entryWrapper.getTableName()));
    }

    public Handle getHandle() {
        return handle;
    }

    public void setHandle(Handle handle) {
        this.handle = handle;
    }
}
